;(function($){
	
	var scrollerable = function(config) {
		config = config || {};
		if(!config.id) {
			config.id = 'scrollerable_'+new Date().getTime();
		}
		
		defaults = scrollerable.defaultConfig;
		
		// 合并默认配置
	    for (var i in defaults) {
	        if (config[i] === undefined) {
	            config[i] = defaults[i];
	        };
	    };
		
		return scrollerable.list[config.id] = new scrollerable.fn.constructor(config);
	}
	
	scrollerable.list = {};
	
	scrollerable.fn = scrollerable.prototype = {
		constructor: function (config) {
			this.config = config;
			this.wrapper = $(config.wrapper);
			this.items = $(config.items);
			this.tid = null;
			this.isPlaying = false;
			this.currentIndex = 0;
			this.maxIndex = this.items.length / config.step / config.blockSize;
			this.itemSize = {
				width: this.items.outerWidth(true), 
				height: this.items.outerHeight(true)
			};
			this._basePosition = -(this._getStepSize()*this.items.length)
			this.init();
			
		},
	
		init: function() {
			var config = this.config,
				wrapper = this.wrapper,
				that = this;
			
			wrapper.mouseover(function() {
				that.stop();
			}).mouseout(function() {
				that.play();
			})
			
			this._patch();
			this.reset();
			this._play(this._getMoveDirection());
			this.play();
		},
		
		go: function(index) {
			return this.goOrBack('go', index);
		},
		
		back: function() {
			return this.goOrBack('back');
		},
		
		goOrBack: function(method, index) {
			if(this.wrapper.is(':animated')) return;
			this.stop();
			var direction = this._getMoveDirection() * (method == 'go' ? 1 : -1);
			if(index !== undefined)
				this.currentIndex = index*direction;
			this.wrapper.stop();
			this._play(direction);
			this.play();
			return this;
		},
		
		play: function() {
			if(this.isPlaying) return true;
			
			var config = this.config,
				that = this;
			
			if(this.config.autoPlay) {
				this.tid = window.setInterval(function() {
					that._play(that._getMoveDirection());
				}, this.config.interval);
			}
			
			return this.isPlaying = true;
		},
		
		stop: function() {
			if(!this.isPlaying) return true;
			window.clearInterval(this.tid);
			return this.isPlaying = false;
		},
		
		reset: function() {
			this.currentIndex = 0;
			this.wrapper.css(this._getMoveAttr(), this._basePosition+'px');
		},
		
		_patch: function() {
			for(i=0; i<this.config.blockSize; ++i) {
				this.wrapper.append(this.items.clone());
				this.wrapper.prepend(this.items.clone());
			}
		},
		
		_play: function(direction) {
			if(this.wrapper.is(':animated')) return;
			if(this.maxIndex == 1) return;
			
			var that = this,
				wrapper = this.wrapper,
				moveAttr = this._getMoveAttr(),
				option = {};
			
			position = this._basePosition + (that._getStepSize()*(Math.abs(that.currentIndex))*that.config.step*direction);
			option[moveAttr] = position + 'px';
			
			if(this.config.beforeScroll) {
				index = Math.abs(that.currentIndex);
				if(index == this.maxIndex) index = 0;
				that.config.beforeScroll.call(this, index, this.items[index]);
			}
			
			wrapper.animate(option, that.config.scrollInterval, function(){
				
				if(Math.abs(that.currentIndex) == that.maxIndex) 
					that.reset();
				
				if(that.config.afterScroll) {
					index = Math.abs(that.currentIndex);
					that.config.afterScroll.call(this, that.items[index]);
				}
				
				that.currentIndex += direction;
				
			});
		},
		
		_getMoveAttr: function() {
			var direction = this.config.direction;
			return direction == 'left' || direction == 'right' ? 'left' : 'top';
		},
		
		_getMoveDirection: function() {
			var direction = this.config.direction;
			return direction == 'left' || direction == 'top' ? -1 : 1;
		},
		
		_getStepSize: function() {
			var direction = this.config.direction;
			return direction == 'left' || direction == 'right' ? 
				this.itemSize.width : this.itemSize.height;
		}
		
	}
	
	scrollerable.fn.constructor.prototype = scrollerable.fn;
	$.scrollerable = function(config) {
		return scrollerable(config);
	},
	
	$.scrollerable.get = function(id) {
		if(id == null) {
			return scrollerable.list;
		} else {
			return scrollerable.list[id] ? scrollerable.list[id] : null;
		}
	}
	
	
	scrollerable.defaultConfig = {
		maskLength: 1,
		step: 1,
		blockSize: 1,
		interval: 3000,
		scrollInterval: 500,
		direction: 'top',
		autoPlay: true
	}
})(jQuery);